//===============================================================================
// Microsoft patterns & practices
// Guidance Explorer Offline Client
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;

namespace GuidanceExplorer.Model
{
    /// <summary>
    /// Represents a base guidance item. It's used to reference an instance of a GuidanceItemFileReference by 
    /// using the Id property.
    /// </summary>
    public class GuidanceItem : IModelItem
    {
        #region Static members

        public static readonly string SourceField = "Source";
        public static readonly string TypeField = "Type";

        /// <summary>
        /// Factory.
        /// </summary>
        /// <returns></returns>
        public static GuidanceItem New()
        {
            return new GuidanceItem();
        }

        #endregion

        #region Private members

        /// <summary>
        /// The title of the item.
        /// </summary>
        private string _title;

        /// <summary>
        /// Unique Id of the item.
        /// </summary>
        private string _id;

		/// <summary>
		/// Schema Id of the item.
		/// </summary>
		private string _schemaId;

        /// <summary>
        /// The library that owns this GuidanceItem
        /// </summary>
        private Library _library;

        /// <summary>
        /// Creation date
        /// </summary>
        private DateTime _date;

        /// <summary>
        /// Relative path to the CSS file that will be used by the item on HTML rendering.
        /// </summary>
        private string _cssPath;

        /// <summary>
        /// The guidance type for this item.
        /// </summary>
        private GuidanceType _guidanceType;

        /// <summary>
        /// Custom data for the item.
        /// </summary>
        private SortedList<String, String> _customData = new SortedList<String, String>();

        /// <summary>
        /// The item referenced in a library.
        /// </summary>
        private GuidanceItemFileReference _referencedItem;

        private Dictionary<string, string> _images = new Dictionary<string,string>();

        private Dictionary<string, string> _imagesMapping = new Dictionary<string, string>();

        #endregion

        /// <summary>
        /// Default protected constructor.
        /// </summary>
        protected GuidanceItem() { }

        #region Public properties

        /// <summary>
        /// The title of the item.
        /// </summary>
        [Browsable(true)]
        [ReadOnly(true)]
        public string Title
        {
            get { return _title; }
            set
            {
                _title = value;
                _customData["title"] = value;
            }
        }

        [Browsable(false)]
        public Dictionary<string, string> AllImages
        {
            get { return _images; }
            set { _images = value; }
        }

        [Browsable(false)]
        public Dictionary<string, string> ImagesMapping
        {
            get { return _imagesMapping; }
        }

        public void AddImage(string name, string path)
        {
            if (_images.ContainsKey(name))
            {
                _images.Remove(name);
            }

            if (File.Exists(path))
            {
                using (FileStream f = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    byte[] bytes = new byte[f.Length];
                    f.Read(bytes, 0, (int)f.Length);
                    _images.Add(name, Convert.ToBase64String(bytes));
                }
            }
        }



        /// <summary>
        /// Returns the temporary path of the desired image
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GenerateImage(string name, string directory, string subdir)
        {
            if (_images.ContainsKey(name))
            {
                string dir;

                if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(subdir))
                {
                    dir = Path.Combine(Path.GetTempPath(), "GE");
                }
                else
                {
                    dir = Path.Combine(directory, subdir);
                }

                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }

                string path = Path.Combine(dir, name);
                using (FileStream f = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                {
                    byte[] bytes = Convert.FromBase64String(_images[name]);
                    f.Write(bytes, 0, bytes.Length);
                }

                if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(subdir))
                {
                    return path;
                }
                else
                {
                    return Path.Combine(subdir, name);
                }
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Get/set the library that owns this GuidanceItem
        /// </summary>
        [Browsable(false)]
        public Library Library
        {
            get { return _library; }
            set 
            {
                _library = value;
                if (_library != null)
                {
                    _customData["Source"] = _library.Caption;
                }
            }
        }

        /// <summary>
        /// GuidanceItem's source
        /// </summary>
        [Browsable(true)]
        [ReadOnly(true)]
        public string Source
        {
            get { return _customData["Source"]; }
        }

        /// <summary>
        /// Unique Id of the item.
        /// </summary>
        [Browsable(true)]
        [ReadOnly(true)]
        public virtual string Id
        {
            get { return _id; }
            set { _id = value.ToLower(); }
        }

        /// <summary>
        /// The guidance type for this item.
        /// </summary>
        [Browsable(false)]
        public GuidanceType GuidanceType
        {
            get { return _guidanceType; }
            set
            {
                _guidanceType = value;

                if (_guidanceType != null)
                {
                    _customData[TypeField] = _guidanceType.DisplayName;
                }
            }
        }

        [Browsable(true)]
        [ReadOnly(true)]
        public string Type
        {
            get
            {
                if (_guidanceType != null)
                {
                    return _guidanceType.DisplayName;
                }
                else
                {
                    return string.Empty;
                }
            }
        }

        /// <summary>
        /// Custom data for the item.
        /// </summary>
        [Browsable(false)]
        public string this[string key]
        {
            get 
            { 
                if (_customData.ContainsKey(key))
                {
                    return _customData[key]; 
                }
                else
                {
                    return string.Empty;
                }
            }
            set { _customData[key] = value; }
        }

        /// <summary>
        /// Relative path to the CSS file that will be used by the item on HTML rendering.
        /// </summary>
        [Browsable(true)]
        [ReadOnly(true)]
        public string CSSFile
        {
            get { return _cssPath; }
            set { _cssPath = value; }
        }

        /// <summary>
        /// Creation date
        /// </summary>
        [Browsable(false)]
        public DateTime DateTime
        {
            get { return _date; }
            set { _date = value; }
        }

        /// <summary>
        /// Creation date
        /// </summary>
        [Browsable(true)]
        [ReadOnly(true)]
        public string Date
        {
            get { return _date.ToLocalTime().ToString("MM/dd/yyyy"); }
        }

        /// <summary>
        /// Custom data for the item.
        /// </summary>
        [Browsable(false)]
        public SortedList<String, String> CustomData
        {
            get { return _customData; }
            set { _customData = value; }
        }

        /// <summary>
        /// The item referenced in a library.
        /// </summary>
        [Browsable(false)]
        public GuidanceItemFileReference ReferencedItem
        {
            get { return _referencedItem; }
            set { _referencedItem = value; }
        }

        #endregion

        /// <summary>
        /// Compare two instances of GuidanceItem.
        /// </summary>
        /// <param name="other">The instance to compare to.</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            GuidanceItem other = obj as GuidanceItem;
            if (other != null)
            {
                return (
                    (this._id == other._id) &&
                    (this._guidanceType == other._guidanceType) &&
                    (this._title == other._title));
            }
            else
            {
                return base.Equals(obj);
            }
        }

        public override int GetHashCode()
        {
            return _id.GetHashCode();
        }

        #region IModelItem Members

        /// <summary>
        /// Every guidance item is editable.
        /// </summary>
        [Browsable(false)]
        public bool IsEditable
        {
            get { return true; }
        }

        /// <summary>
        /// Check what kind of model item can be droped.
        /// </summary>
        [Browsable(false)]
        public bool CanDrop(IModelItem modelItem)
        {
            return false;
        }

        [Browsable(false)]
        public string SelectedItem
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        #endregion
    }
}

